/**
 * RecvBase.java
 * 版权所有(C) 2013
 * 创建者:cuiran 2013-11-27 上午10:42:04
 */
package com.ghyf.mplay.net.common;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import android.content.Context;
import android.util.Log;

import com.ghyf.mplay.application.CookieConstants;
import com.ghyf.mplay.application.UserInfoSingleton;
import com.ghyf.mplay.util.LogUtil;
import com.ghyf.mplay.util.StorageUtil;
import com.ghyf.mplay.value.ConstantValue;

/**
 *  参数常量类
 * @author cuiran
 * @version 1.0.0
 */
public class RecvBase {
	
	protected static final String TAG = "RecvBase";
	
	
	public static boolean isStop = false;
	public static final String charset="gb2312";
	public static final String charset_iso="iso-8859-1";
	public static final String charset_utf="UTF-8";
	protected static final int PORT_DEFAULT_LISTEN = 18810;
	protected static final int PORT_TEXT_LISTEN = 18820;
	protected static final int PORT_FILE_LISTEN = 18830;
	
	protected int port_listen = 18810;
	protected int port_server = 18600;
	protected Context mContext=null;
	
	
	protected static final String LIVE_VIDEO_HOST="238.1.1.1";
	protected static final int LIVE_VIDEO_DEFAULT_LISTEN=18861;
	protected static final int LIVE_VIDEO_PREPARE_LISTEN=18862; 
	
	
	//ACTION 
	/**接收播放控制指令广播action****/
	public static final String ACTION_CMD_CONTROL ="com.ghyf.mplay.cmd_control";
	/**接收直播指令广播action****/
	public static final String ACTION_CMD_MAIN ="com.ghyf.mplay.cmd_main";
	/**发送下载进度给控制中心广播action****/
	public static final String ACTION_CMD_SEND ="com.ghyf.mplay.cmd_send";
	
//	protected int maxPacketLength = 							1500;
	protected static final int packetHeaderLength = 			40;
	protected static final int heartbeatReportPacketLength = 	186;
	protected static final int heartbeatTrainReportPacketLength=482;
	protected static final int ackPacketLength = 				436;
//	protected static final int statusReportPacketLength = 		1320;
//	protected  			 int curListReportPacketLength = 		0;		// 不固定的包长
//	protected 			 int listDataReportPacketLength = 		0;		// 不固定的包长
//	protected 	 		 int emIDReportPacketLength =			0;		// 不固定的包长
	protected static final int emTextReportPacketLength = 		1104;
	protected static final int listHeaderLength = 				64;
	protected static final int setPriorityTextLength = 			1066;
	protected static final int stopTextLength = 			    32;
	protected static final int setConfigTextLength = 			614;
	/**获取当前在播画面数据长度***/
	protected static final int curDisplayDataLength = 			24;
	protected static final int streamDataLength = 			    19;
	protected static final int ipDataLength = 			        15;
	protected static final int setListTextLength = 			    357;
	protected static final int getLogTextLength = 			    132;
	protected static final int maxSetNormalTextLength =			1280;
	
	protected static final int deviceIDLength = 				10;
	protected static final int packetHeaderReservedLength = 	17;
	protected static final int versionLength = 					20;
	protected static final int heartbeatReportPacketReservedLength = 36;
	protected static final int ackPacketExecDesLength = 		256;
	protected static final int ackPacketReservedLength = 		127;
	protected static final int setVolumeDataLength = 			1;
	/**
	 * 紧急模块的UID
	 */
	public static final int UID_URGENT = 				     	100;
	
	/**
	 * 服务端发送到客户端
	 */
	protected static final byte STX_SERVER2CLIENT = 			(byte)0xFE;
	/**
	 * 客户端发送到服务端
	 */
	protected static final byte STX_CLIENT2SERVER = 			(byte)0xEF;
	
	/**命令执行结果***/
	protected static final int CMD_ACK = 						99;
	/**心跳请求***/
	protected static final int CMD_HEART_REQUEST = 				100;
	/**心跳返回***/
	protected static final int CMD_HEART_REPORT = 				101;
	
	
	
	/**心跳请求2***/
	protected static final short CMD_HEART_REQUEST2 = 			102;
	/**心跳返回2***/
	protected static final short CMD_HEART_REPORT2 = 			103;
	
	/**列车到发信息***/
	protected static final short CMD_ATS_INFO = 				110;
	
	/**获取当前设备状态***/
	protected static final short CMD_STATUS_REQUEST = 			200;
	/**返回当前设备状态***/
	protected static final short CMD_STATUS_REPORT = 			201;
	/**获取当前在播画面***/
	public	 static final short CMD_STATUS_GETCURDIAPLAY = 		202;
	/**设备唤醒。如设备不支持该命令，则需支持WOL方式唤醒***/
	public static final short CMD_CONTROL_POWERON = 			300;
	/**设备关闭***/
	public static final short CMD_CONTROL_POWEROFF = 			302;
	/**设备重启***/
	public 	  static final short CMD_CONTROL_RESET = 			304;
	/**软件重启***/
	public 	  static final short CMD_CONTROL_RESTARTSOFTWARE =  306;
	/**节目单控制-播放***/
	public    static final short CMD_CONTROL_PLAY = 			310;
	/**节目单控制-停止***/
	public    static final short CMD_CONTROL_STOP = 			312;
	/**节目单控制-从暂停中恢复***/
	public    static final short CMD_CONTROL_REPLAY = 			314;
	/**节目单控制-暂停***/
	public    static final short CMD_CONTROL_PAUSEPLAY = 		316;
	/**节目单控制-切换模板***/
	public    static final short CMD_CONTROL_TAKE = 			318;
	/**节目单控制-播出视频流***/
	public    static final short CMD_CONTROL_PLAYSTREAM = 		320;
	/**节目单控制-播出本地视频***/
	public    static final short CMD_CONTROL_PLAYLOCAL = 		322;
	/**节目单控制-播出视频流***/
	public    static final short CMD_CONTROL_PLAYSTREAM_Z = 	1320;
	/**节目单控制-播出本地视频***/
	public    static final short CMD_CONTROL_PLAYLOCAL_L = 		1322;
	/**节目单控制-播出本地视频***/
	public    static final short CMD_CONTROL_PLAYLOCAL_1 = 		3221;
	/**开屏***/
	public    static final short CMD_CONTROL_SCREENON = 		324;
	/**关屏***/
	public    static final short CMD_CONTROL_SCREENOFF = 		326;
	
	
	/**音量控制【带扩展参数】***/
	public    static final short CMD_CONTROL_SETVOLUME = 		350;
	/**音量控制-静音恢复***/
	public    static final short CMD_CONTROL_SOUNDON = 			352;
	/**音量控制-静音***/
	public static final short CMD_CONTROL_SOUNDMUTE = 			354;
	/**进入紧急模式，触发紧急模板***/
	public static final short CMD_CONTROL_STARTEMERGENCY = 		360;
	/**取消紧急模式***/
	public static final short CMD_CONTROL_STOPEMERGENCY = 		362;
	/**得到当前播放的紧急信息ID【带扩展参数】***/
	protected static final short CMD_CONTROL_GETEMERGENCYID = 	364;
	/**返回当前播放的紧急信息ID【带扩展参数】***/
	protected static final short CMD_CONTROL_EMERGENCYIDREPORT =365;
	/**得到当前播放的紧急信息内容【带扩展参数】***/
	protected static final short CMD_CONTROL_GETEMERGENCYTEXT =	366;
	/**返回当前播放的紧急信息内容【带扩展参数】***/
	protected static final short CMD_CONTROL_EMERGENCYTEXTREPORT =367;
	/**模板控制-显示指定的组【带扩展参数】***/
	public static final short CMD_CONTROL_GROUPSHOW = 			370;
	/**模板控制-隐藏指定的组【带扩展参数】***/
	public static final short CMD_CONTROL_GROUPHIDE = 			372;
	/**获取当前节目单列表【带扩展参数】***/
	protected static final short CMD_LIST_GETCURLIST = 			500;
	/**返回当前节目单列表【带扩展参数】***/
	protected static final short CMD_LIST_CURLISTREPORT	 = 		501;
	/**获取指定节目单的详细信息【带扩展参数】***/
	protected static final short CMD_LIST_GETLISTDATA = 		502;
	/**返回指定节目单的详细信息【带扩展参数】***/
	protected static final short CMD_LIST_LISTDATAREPORT = 		503;
	/**删除节目单【带扩展参数】***/
	protected static final short CMD_LIST_DELETE = 				504;
	/**PLAY***/
	protected static final short CMD_LIST_PLAY = 				506;
	/**设置带优先级的文本【带扩展参数】***/
	public    static final short CMD_TEXT_SETPROIRITY = 		600;
	/**设置一般文本【带扩展参数】***/
	public    static final short CMD_TEXT_SETNORMAL = 			602;
	/**停止所有紧急信息***/
	public    static final short CMD_TEXT_STOP		 = 			604;
	/***发送程序和配置变化通知***/
	public 	  static final short CMD_FILE_SETCONFIG	 = 			700;
	/***发送节目单变化通知***/
	public    static final short CMD_FILE_SETLIST = 			702;
	/***上传日志***/
	public    static final short CMD_FILE_GETLOG = 				704;
	/**串口命令***/
	public static final short CMD_SERIAL_REQUEST = 				800;
	/**串口回应***/
	protected static final short CMD_SERIAL_REPORT = 			801;

	protected static final int ERR_OK = 						0;
	protected static final int ERR_PH_STX = 					-100;
	protected static final int ERR_PH_CMDID = 					-101;						
	protected static final int ERR_PH_PACKETID = 				-102;						
	protected static final int ERR_PH_DEVICEID = 				-110;						
	protected static final int ERR_PH_DATALENGTH = 				-120;						
	protected static final int ERR_PH_DATAERROR = 				-121;						
	
	/**指令执行成功，无设备报警及错误代码***/
	protected static final int NET_ACK = 						0;
	/**指令执行成功，无设备报警及错误代码***/
	protected static final int NET_LIST_OK = 					0;
	/**文件下载进度***/
	protected static final int NET_DOWNLOADPROGRESS =			1;
	/**软件、配置、节目单安装进度***/
	protected static final int NET_INSTALLPROGRESS = 			2;
	/**指令未能成功执行***/
	protected static final int NET_NAK = 						41;
	/**设备无法连接***/
	protected static final int NET_CANNT_CONNECT = 				42;
	/**设备未准备好***/
	protected static final int NET_DEVICE_NOTREADY = 			43;
	/**温度报警***/
	protected static final int NET_TEMP_ALARM = 				44;
	/**未能得到有效报文***/
	protected static final int NET_INVALID_PACKET = 			99;
	/**硬件报警***/
	protected static final int NET_HARDWARE_ALARM = 			101;
	/**串口错误***/
	protected static final int NET_SERIAL_ERROR = 				103;
	/**存储空间报警***/
	protected static final int NET_STORAGE_ALARM = 				111;
	/**软件运行报警***/
	protected static final int NET_SOFTWARE_ALARM = 			201;
	/**优先级错误***/
	protected static final int NET_PRIORITY_ERROR = 			202;
	/**收到错误数据***/
	protected static final int NET_RECV_DATA_ERROR = 			203;
	/**软件安装报警***/
	protected static final int NET_SOFTWARE_INSTALL_ALARM = 	204;
	/**配置安装报警***/
	protected static final int NET_CONFIG_INSTALL_ALARM = 		205;
	/**节目单不存在***/
	protected static final int NET_LIST_NOT_EXIST = 			306;
	/**文件被占用，被锁定***/
	protected static final int NET_LIST_LOCKED = 				307;
	/**节目单不完整，指节目单内其他素材文件有缺失***/
	protected static final int NET_LIST_DAMAGED = 				308;
	/**未知的UID，当服务器发送的文本消息UID不存在时，播放设备返回此错误***/
	protected static final int NET_UNKNOWN_UID = 				409;
	/**未知的GID,当服务器控制组的隐藏和显示时所指定的GID不存在，则返回此错误***/
	protected static final int NET_UNKNOWN_GID = 				410;
	
	public static String playList;
	
	

	public RecvBase(){
	}

	protected void WriteFixBytes(DataOutputStream dout, byte[] bWrite, int length)
	{
		if(length <= 0)
		{	return;
		}
		byte[] bNull = new byte[length];			
		try
		{
			if(bWrite.length <= length)
			{
				dout.write(bWrite, 0, bWrite.length);				// write bWrite.length bytes
				dout.write(bNull, 0, length - bWrite.length);		// write remain bytes
			}
			else
			{
				dout.write(bWrite, 0, length);						// write length bytes, ignore others
			}
		}
		catch(IOException e)
		{
			Log.i(TAG, "RecvBase.WriteFixBytes() -- catch IOException: " + e.getLocalizedMessage());
		}
	}
	
	protected void WriteListHeaderBytes(DataOutputStream dout,  int length){
		byte[] bNull = new byte[length];	
		try
		{
			if(length <= 0)
			{	return;
			}
			dout.writeByte((byte)0);
			WriteFixBytes(dout,playList.getBytes(), listHeaderLength-14);  	
			dout.write(bNull, 0, 13);  	
		}catch(Exception e){
			Log.e(TAG, "RecvBase.WriteListHeaderBytes() -- catch IOException: ", e);
		}
		
	}
	
	protected byte[] makeHeartbeatPacket(int temp)
	{
		byte[] bNull = new byte[heartbeatTrainReportPacketLength];			
		try
		{
			// first make a DataOutputStream
			ByteArrayOutputStream baOut = new ByteArrayOutputStream(heartbeatTrainReportPacketLength);
			DataOutputStream dout = new DataOutputStream(baOut);
			
			// then write packe theader
			dout.writeByte(STX_CLIENT2SERVER);											// STX
			dout.writeShort(CMD_HEART_REPORT);											// CmdID
			long currentTimeMillis = System.currentTimeMillis();
			dout.writeLong(currentTimeMillis);											// use timemillis instead of "timestamp and tickCount"
			WriteFixBytes(dout, GData.strDeviceID.getBytes(), deviceIDLength);			// DeviceID
			dout.write(bNull, 0, packetHeaderReservedLength);  							// Reserved
			dout.writeShort(heartbeatTrainReportPacketLength - packetHeaderLength);			// DatatLength
	
			// write packet data
			dout.writeShort((short)GData.deviceStatus);										// DeviceStatus
			WriteFixBytes(dout, GData.strFirmwareVersion.getBytes(), versionLength);	// FirmwareVersion
			WriteFixBytes(dout, GData.strSoftwareVersion.getBytes(), versionLength);	// SoftwareVersion
			WriteFixBytes(dout, GData.strConfigVersion.getBytes(), versionLength);  	// ConfigVersion
			WriteListHeaderBytes(dout, listHeaderLength);  									// CurList, 注意此处！
			//write cpu %
			dout.writeByte(StorageUtil.readUsage());
			//write ram %
			dout.writeByte(StorageUtil.getRamUse(mContext));	
			//write 系统硬盘 总量（MB）
			dout.writeInt((int)StorageUtil.getTotalExternalMemorySize());	
			//write 系统硬盘剩余（MB）
			dout.writeInt((int)StorageUtil.getAvailableExternalMemorySize());	
			//write 数据硬盘总量（MB）
			dout.writeInt((int)StorageUtil.getDataTotalSize());	
			//write 数据硬盘剩余（MB）
			dout.writeInt((int)StorageUtil.getDataFreeSize());	
			//write temperature 
			if(temp<=0){
				temp=0;
			}
			dout.writeShort(temp);	
			//0=不支持；1=未处于紧急状态，2=正在播放紧急信息 EmergStatus
			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.EmergStatus, ConstantValue.EMERGSTATUS_NO));
			//0=不支持；1=没有视频；2=本地；1n直播通道n（如11表示当前播放直播通道1） VideoStatus
			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.VideoStatus,ConstantValue.VIDEOSTATUS_YES));
			//0=不支持；1=静音；2=未静音  AudioStatus
			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.AudioStatus, ConstantValue.AUDIOSTATUS_YES));
			//当前音量值0-100  AudioVolume 
			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.AudioVolume,0));
			
			dout.write(bNull, 0, heartbeatReportPacketReservedLength);  				// Reserved2			
			dout.write(bNull, 0, ackPacketExecDesLength);  				// Reserved2	
			// output byte[]
			LogUtil.i(TAG, "deviceCode="+GData.strDeviceID);
			return baOut.toByteArray();
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.makeHeartbeatPacket() -- catch IOException: " + e.getLocalizedMessage());
			return null;
		}
		
	}
	//演示
	protected byte[] makeHeartbeatPacket_yanshi(int temp)
	{
		byte[] bNull = new byte[heartbeatReportPacketLength];			
		try
		{
			// first make a DataOutputStream
			ByteArrayOutputStream baOut = new ByteArrayOutputStream(heartbeatReportPacketLength);
			DataOutputStream dout = new DataOutputStream(baOut);
			
			// then write packe theader
			dout.writeByte(STX_CLIENT2SERVER);											// STX
			dout.writeShort(CMD_HEART_REPORT);											// CmdID
			long currentTimeMillis = System.currentTimeMillis();
			dout.writeLong(currentTimeMillis);											// use timemillis instead of "timestamp and tickCount"
			WriteFixBytes(dout, GData.strDeviceID.getBytes(), deviceIDLength);			// DeviceID
			dout.write(bNull, 0, packetHeaderReservedLength);  							// Reserved
			dout.writeShort(heartbeatReportPacketLength - packetHeaderLength);			// DatatLength
	
			// write packet data
			dout.writeShort(GData.deviceStatus);										// DeviceStatus
			WriteFixBytes(dout, GData.strFirmwareVersion.getBytes(), versionLength);	// FirmwareVersion
			WriteFixBytes(dout, GData.strSoftwareVersion.getBytes(), versionLength);	// SoftwareVersion
			WriteFixBytes(dout, GData.strConfigVersion.getBytes(), versionLength);  	// ConfigVersion
			WriteFixBytes(dout,playList.getBytes(), listHeaderLength);
			//write cpu %
//			dout.writeByte((byte)StorageUtil.readUsage());
//			//write ram %
//			dout.writeByte((byte)StorageUtil.getRamUse(mContext));	
//			//write 系统硬盘 总量（MB）
//			dout.writeInt((int)StorageUtil.getTotalExternalMemorySize());	
//			//write 系统硬盘剩余（MB）
//			dout.writeInt((int)StorageUtil.getAvailableExternalMemorySize());	
//			//write 数据硬盘总量（MB）
//			dout.writeInt((int)StorageUtil.getDataTotalSize());	
//			//write 数据硬盘剩余（MB）
//			dout.writeInt((int)StorageUtil.getDataFreeSize());	
//			//write temperature 
//			dout.writeShort(temp);	
//			//0=不支持；1=未处于紧急状态，2=正在播放紧急信息 EmergStatus
//			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.EmergStatus, ConstantValue.EMERGSTATUS_DEFAULT));
//			//0=不支持；1=没有视频；2=本地；1n直播通道n（如11表示当前播放直播通道1） VideoStatus
//			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.VideoStatus,ConstantValue.VIDEOSTATUS_DEFAULT));
//			//0=不支持；1=静音；2=未静音  AudioStatus
//			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.AudioStatus, ConstantValue.AUDIOSTATUS_DEFAULT));
//			//当前音量值0-100  AudioVolume 
//			dout.writeByte(UserInfoSingleton.getInt(CookieConstants.AudioVolume,0));
			//--------------进行更改
			dout.write(bNull, 0, heartbeatReportPacketReservedLength-14);  				// Reserved2			
//			dout.write(bNull, 0, ackPacketExecDesLength);  				// Reserved2	
			// output byte[]
			return baOut.toByteArray();
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.makeHeartbeatPacket() -- catch IOException: " + e.getLocalizedMessage());
			return null;
		}
		
	}
	
	protected byte[] makeHeartbeatPacket2()
	{
		byte[] bNull = new byte[heartbeatReportPacketLength];			
		try
		{
			// first make a DataOutputStream
			ByteArrayOutputStream baOut = new ByteArrayOutputStream(heartbeatReportPacketLength);
			DataOutputStream dout = new DataOutputStream(baOut);
			
			// then write packe theader
			dout.writeByte(STX_CLIENT2SERVER);											// STX
			dout.writeShort(CMD_HEART_REPORT2);											// CmdID
			long currentTimeMillis = System.currentTimeMillis();
			dout.writeLong(currentTimeMillis);											// use timemillis instead of "timestamp and tickCount"
			WriteFixBytes(dout, GData.strDeviceID.getBytes(), deviceIDLength);			// DeviceID
			dout.write(bNull, 0, packetHeaderReservedLength);  							// Reserved
			dout.writeShort(heartbeatReportPacketLength - packetHeaderLength);			// DatatLength
	
			// write packet data
			dout.writeShort(GData.deviceStatus);										// 2DeviceStatus 设备状态。0：故障；>0：故障
			
			dout.writeShort(0x0100);													// 2FirmwareVersion 固件版本号，如：0x0100
			WriteFixBytes(dout, GData.strFirmwareVersion.getBytes(), versionLength);	// 20FirmwareVersion 固件版本号，如：”1.0.0.1”
			
			dout.writeShort(0x0100);													// 2SoftwareVersion 软件版本号，如：0x0100
			WriteFixBytes(dout, GData.strSoftwareVersion.getBytes(), versionLength);	// 20SoftwareVersion 软件版本号，如：”1.0.0.1”
			
			dout.write(bNull, 0, 100);  				// Reserved2			
			
			// output byte[]
			return baOut.toByteArray();
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.makeHeartbeatPacket() -- catch IOException: " + e.getLocalizedMessage());
			return null;
		}
		
	}
	
	protected byte[] makeAckPacket(short ackCmdID, int ackTimestamp, int ackTickCount, short execResult, byte execProgress, String strExecDes)
	{
		byte[] bNull = new byte[ackPacketLength];			
		try
		{
			// first make a DataOutputStream
			ByteArrayOutputStream baOut = new ByteArrayOutputStream(ackPacketLength);
			DataOutputStream dout = new DataOutputStream(baOut);
			
			// then write packe theader
			dout.writeByte(STX_CLIENT2SERVER);									// STX
			dout.writeShort(CMD_ACK);											// CmdID
			long currentTimeMillis = System.currentTimeMillis();
			dout.writeLong(currentTimeMillis);									// use timemillis instead of timestamp and tickCount
			WriteFixBytes(dout, GData.strDeviceID.getBytes(), deviceIDLength);	// DeviceID
			dout.write(bNull, 0, packetHeaderReservedLength);  					// Reserved
			dout.writeShort(ackPacketLength - packetHeaderLength);				// DatatLength
	
			// write packet data
			dout.writeShort(ackCmdID);											// ACKCmdID
			dout.writeInt(ackTimestamp);										// ackTimestamp
			dout.writeInt(ackTickCount);										// ackTickCount
			dout.writeShort(execResult);										// execResult
			dout.writeByte(execProgress);										// execProgress
			WriteFixBytes(dout, strExecDes.getBytes(charset), ackPacketExecDesLength); // strExecDes
			dout.write(bNull, 0, ackPacketReservedLength);  					// Reserved			
			
			// output byte[]
			return baOut.toByteArray();
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.MakeAckPacket() -- catch IOException: " + e.getLocalizedMessage());
			return null;
		}		
	}
	/**
	 * 客户端发送给服务器<br>
	 * 2013-11-27 下午4:57:14
	 * @param ackCmdID ACK对应的命令
	 * @param ackTimestamp ACK对应命令的报文编号
	 * @param ackTickCount ACK对应命令的报文编号
	 * @param execResult 命令执行结果
	 * @param execProgress 执行进度：xx%，仅当有效ExecResult=1或2时有效
	 * @param strExecDes 命令执行结果描述，可为空，即“\0”
	 * @param so_out
	 * @param inetAddr_in
	 *
	 */
	protected void sendAck(short ackCmdID, int ackTimestamp, int ackTickCount, short execResult, byte execProgress, String strExecDes, DatagramSocket so_out, InetAddress inetAddr_in)
	{
		try
		{
			byte[] buf_out =makeAckPacket(ackCmdID, ackTimestamp, ackTickCount, execResult, execProgress, strExecDes);
			DatagramPacket pkt_out = new DatagramPacket(buf_out, buf_out.length, inetAddr_in, port_server);
			
			// send packet
	        so_out.send(pkt_out);
			String ip_in = inetAddr_in.getHostAddress();
			LogUtil.i(TAG, "RecvBase.run() -- Send ACK to:ackCmdID("+ackCmdID+")   IP(" + ip_in + ":" + port_server + ") Length(" + pkt_out.getLength() + ")");
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.SendAck() -- catch IOException: " + e.getLocalizedMessage());
			return;
		}		
	}
	
	protected void sendAck(short ackCmdID, int ackTimestamp, int ackTickCount, short execResult, byte execProgress, String strExecDes, DatagramSocket so_out, InetAddress inetAddr_in,int in_port)
	{
		try
		{
			byte[] buf_out =makeAckPacket(ackCmdID, ackTimestamp, ackTickCount, execResult, execProgress, strExecDes);
			String ip_in = inetAddr_in.getHostAddress();
			DatagramPacket pkt_out = new DatagramPacket(buf_out, buf_out.length, inetAddr_in, in_port);
			
			// send packet
	        so_out.send(pkt_out);
			LogUtil.i(TAG, "RecvBase.run() -- Send ACK to: IP(" + ip_in + ":" + in_port + ") execProgress("+execProgress+")  Length(" + pkt_out.getLength() + ")");
		}
		catch(IOException e)
		{
			LogUtil.i(TAG, "RecvBase.SendAck() -- catch IOException: " + e.getLocalizedMessage());
			return;
		}		
	}
	
}
